#include "serializer/io.h"
#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <optional>

using namespace serializer;

// ============================================================================
// 测试：与 serializer 命名空间同名的自由函数在全局命名空间定义时不应被 ADL 拾取
// 目的：验证“必须与类型同一命名空间”的约束
// ============================================================================
struct GlobalFreeFuncType
{
    int x;
    bool operator==(const GlobalFreeFuncType & other) const { return x == other.x; }
};

static bool s_global_serialize_seen = false;
static bool s_global_deserialize_seen = false;

/**
 * 全局命名空间中的自由函数（用于负例断言，不应被 ADL 选中）
 * 参数:
 * - writer 写入器（未使用）
 * - v 需要序列化的对象（未使用）
 * - options 序列化选项（未使用）
 * 返回值: 无
 * 异常: 无（此函数仅用于记录是否被误选）
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
serialize_value(Writer & /*writer*/, const GlobalFreeFuncType & /*v*/, const Options & /*options*/)
{
    // 这是“错误位置”的自由函数（全局命名空间），不应被 ADL 选中
    s_global_serialize_seen = true;
}

/**
 * 全局命名空间中的自由函数（用于负例断言，不应被 ADL 选中）
 * 参数:
 * - reader 读取器（未使用）
 * - options 序列化选项（未使用）
 * - tag 类型标签（未使用）
 * 返回值: 返回一个默认构造的 GlobalFreeFuncType（未使用）
 * 异常: 无（此函数仅用于记录是否被误选）
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
GlobalFreeFuncType
deserialize_value(Reader & /*reader*/, const Options & /*options*/, type_tag_t<GlobalFreeFuncType>)
{
    // 这是“错误位置”的自由函数（全局命名空间），不应被 ADL 选中
    s_global_deserialize_seen = true;
    return GlobalFreeFuncType{};
}

// 提供一个稳定的 tag_invoke 默认路径以确保类型可被序列化

/**
 * 为 GlobalFreeFuncType 提供 tag_invoke 的序列化实现（用于确保类型可参与测试）
 * 参数:
 * - writer 写入器，满足 writer 概念
 * - v 需要序列化的对象
 * - options 序列化选项
 * 返回值: 无
 * 异常: 由底层 writer 或序列化逻辑抛出
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
tag_invoke(serialize_tag_t, Writer & writer, const GlobalFreeFuncType & v, const Options & options)
{
    tag_invoke_fn(serialize_tag, writer, v.x, options);
}

/**
 * 为 GlobalFreeFuncType 提供 tag_invoke 的反序列化实现（用于确保类型可参与测试）
 * 参数:
 * - reader 读取器，满足 reader 概念
 * - options 序列化选项
 * 返回值: 反序列化得到的 GlobalFreeFuncType 对象
 * 异常: 由底层 reader 或序列化逻辑抛出
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
GlobalFreeFuncType
tag_invoke(deserialize_tag_t<GlobalFreeFuncType>, Reader & reader, const Options & options)
{
    GlobalFreeFuncType out{};
    out.x = tag_invoke_fn(deserialize_tag<int>, reader, options);
    return out;
}

TEST(cpo_adl_free_functions_negative_test, global_namespace_free_functions_must_not_bind)
{
    vector_writer writer;
    default_options options{};

    s_global_serialize_seen = false;
    s_global_deserialize_seen = false;

    GlobalFreeFuncType original{77};
    serialize(writer, original, options);
    vector_reader reader(writer.data());
    auto deserialized = deserialize<GlobalFreeFuncType>(reader, options);

    // 若全局自由函数被 ADL 调用，这两个标志会置位；此处应保持为 false
    EXPECT_FALSE(s_global_serialize_seen);
    EXPECT_FALSE(s_global_deserialize_seen);
    EXPECT_EQ(deserialized, original);
}

// ============================================================================
// 测试：随机字节序与 optional 组合，确保 default_implementations 中的 tag_invoke 覆盖正常
// ============================================================================
TEST(cpo_adl_free_functions_negative_test, optional_roundtrip_and_byte_order_variants)
{
    default_options options{};
    auto le = options.with_byte_order(byte_order::little_endian);
    auto be = options.with_byte_order(byte_order::big_endian);

    {
        vector_writer writer;
        std::optional<int> ov = 123;
        serialize(writer, ov, le);
        vector_reader reader(writer.data());
        std::optional<int> out = deserialize_cpo(reader, le, type_tag<std::optional<int>>);
        EXPECT_EQ(out, ov);
    }
    {
        vector_writer writer;
        std::optional<int> ov = std::nullopt;
        serialize(writer, ov, be);
        vector_reader reader(writer.data());
        std::optional<int> out = deserialize_cpo(reader, be, type_tag<std::optional<int>>);
        EXPECT_EQ(out, ov);
    }
}